﻿/* main.c */
#include "app.h"

/*******************************************************************************
 * Definitions
 ******************************************************************************/

#define APP_NN_SAMPLE_ELEM_NUM  100

/*******************************************************************************
 * Variables
 ******************************************************************************/

uint32_t tick_counter_val; /* 用于计时. */

nn_layer_t app_nn_layer1;
nn_layer_t app_nn_layer2;

float    app_nn_input[1];          /* layer1->n_input = 1. */
float    app_nn_layer1_output[10]; /* layer1->n_output = 10. */
float    app_nn_layer2_output[1];  /* layer1->n_output = 1. */
float *  app_nn_output;

/* samples. */
float x[APP_NN_SAMPLE_ELEM_NUM];    /* 样本输入. */
float y[APP_NN_SAMPLE_ELEM_NUM];    /* 实际值. */
float y_nn[APP_NN_SAMPLE_ELEM_NUM]; /* nn预测值. */

/*******************************************************************************
 * Prototypes
 ******************************************************************************/
void     app_nn_init(void);
float *  app_nn_forward_pq(float *input);
float *  app_nn_forward_arm(float *input);

/*******************************************************************************
 * Code
 ******************************************************************************/
/*!
 * @brief Main function
 */
int main(void)
{
    BOARD_InitHardware();
    PRINTF("\r\nPowerQuad NN Examples.\r\n\r\n");

    /* 随机生成样本点. 输入x在[-1, 1]. */
    srand(1); /* 初始化随机数发生器种子. */ /* rand() */
    for (uint32_t i = 0u; i < APP_NN_SAMPLE_ELEM_NUM; i++)
    {
        x[i] = -1 + 0.01f * (rand()%200);
        y[i] = x[i] * x[i]; /* 使用预先 知道的规律计算真实值. */
    }

    app_nn_init(); /* 初始化网络. */
    float app_nn_err_max = 0.0f;
    for (uint32_t i = 0u; i < APP_NN_SAMPLE_ELEM_NUM; i++)
    {
        app_nn_input[0] = x[i];

        /* 使用人工神经网络预测值. */
        TimerCount_Start(); /* 开始计时 */
        app_nn_output = app_nn_forward_arm(app_nn_input); /* app_nn_forward_pq. */
        TimerCount_Stop(tick_counter_val);

        /* 记录误差. */
        y_nn[i] = app_nn_output[0];
        if (fabs(y_nn[i] - y[i]) >= app_nn_err_max)
        {
            app_nn_err_max = fabs(y_nn[i] - y[i]);
        }
        PRINTF("[%3d]. (%9f)^2: %f in %d us\r\n",i, x[i], y_nn[i], tick_counter_val/96);
    }

    PRINTF("app_nn_err_max: %f\r\n done\r\n", app_nn_err_max);

    while (1)
    {
    }
}

void app_nn_init(void)
{
    nn_init();

    nn_layer_init(&app_nn_layer1, 1, 10, nn_param_hidden_weight, nn_param_hidden_bias);
    nn_layer_init(&app_nn_layer2, 10, 1, nn_param_out_weight, nn_param_out_bias);
}

float * app_nn_forward_pq(float *input)
{
    nn_layer_forward_linear_pq(&app_nn_layer1, input, app_nn_layer1_output);
    nn_layer_activate_tanh_pq(app_nn_layer1_output, app_nn_layer1_output, app_nn_layer1.n_output);
    nn_layer_forward_linear_pq(&app_nn_layer2, app_nn_layer1_output, app_nn_layer2_output);

    return app_nn_layer2_output;
}

float * app_nn_forward_arm(float *input)
{
    nn_layer_forward_linear_arm(&app_nn_layer1, input, app_nn_layer1_output);
    nn_layer_activate_tanh_arm(app_nn_layer1_output, app_nn_layer1_output, app_nn_layer1.n_output);
    nn_layer_forward_linear_arm(&app_nn_layer2, app_nn_layer1_output, app_nn_layer2_output);

    return app_nn_layer2_output;
}

/* EOF. */

